﻿#region Using Directives

    using System;
    using System.Linq;

    using Csla;

    using MarketPulse.BusinessLogic.Core;
    using MarketPulse.BusinessLogic.Common;
    using MarketPulse.BusinessLogic.Common.Criteria;
    using MarketPulse.BusinessLogic.Private.Criteria;

#endregion

namespace MarketPulse.BusinessLogic.Private
{
    /// <summary>
    /// This class represents an accreditation that a shopper must complete before being allowed to perform shops for the client the accreditation represents.
    /// </summary>
    [Serializable]
    [Csla.Server.ObjectFactory("MarketPulse.DataAccess.Factory.AccreditationFactory, MarketPulse.DataAccess.Factory")]
    public class Accreditation : MarketPulseBase<Accreditation>
    {      

        #region Constructors

            /// <summary>
            /// default constructor is private in order to (try to) enforce construction
            /// only via the static factory methods provided.
            /// </summary>
            private Accreditation()
            {
            }

        #endregion

        #region Methods

            #region Factory Methods

                /// <summary>
                /// Gets an Accreditation object described by the Guid supplied (via the DataPortal client proxy)
                /// </summary>
                /// <param name="guid">The Guid of the Accreditation to retrieve</param>
                /// <returns>The populated Accreditation object</returns>
                public static Accreditation Get(Guid guid)
                {
                    return DataPortal.Fetch<Accreditation>(new SingleCriteria<Guid>(guid));
                }

                /// <summary>
                /// Gets an Accreditation object described by the Guid and VersionID supplied (via the DataPortal client proxy)
                /// </summary>
                /// <param name="guid">The Guid of the Accreditation to retrieve</param>
                /// /// <param name="versionID">The VersionID of the Accreditation to retrieve</param>
                /// <returns>The populated Accreditation object</returns>
                public static Accreditation Get(Guid guid, long versionID)
                {
                    return DataPortal.Fetch<Accreditation>(new UniqueAccreditationCriteria(guid, versionID));
                }

                /// <summary>
                /// Method used to update the supplied Accreditation object (via the DataPortal client proxy)
                /// </summary>
                /// <param name="visit">The Accreditation object to update</param>
                /// <returns>A Accreditation object that represents the Accreditation after the update</returns>
                public static Accreditation Update(Accreditation visit)
                {
                    return DataPortal.Update<Accreditation>(visit);
                }

            #endregion

            #region Business Process Methods

                /// <summary>
                /// Method used to fail an attempt by a User to become Accredited
                /// </summary>
                /// <param name="userGuid">The GUID for the user that made the attempt</param>
                public void FailUserAttempt(Guid? userGuid)
                {
                    AddUserAccreditationAttempt(userGuid, false);
                }

                /// <summary>
                /// Method used to pass an attempt by a User to become Accredited
                /// </summary>
                /// <param name="userGuid">The GUID for the user that made the attempt</param>
                public void AccreditUserAttempt(Guid? userGuid)
                {
                    AddUserAccreditationAttempt(userGuid, true);
                }

            #endregion

            #region Local Methods

                /// <summary>
                /// Method used to add a User Accreditation attempt to this Accreditation
                /// </summary>
                /// <param name="userGuid">The GUID for the user that made the attempt</param>
                /// <param name="accredited">Whether the use should be accredited or not</param>
                private void AddUserAccreditationAttempt(Guid? userGuid, bool accredited)
                {
                    UserAccreditation accreditationAttempt = UserAccreditation.New();
                    accreditationAttempt.AccreditationGUID = this.GUID;
                    accreditationAttempt.VersionID = this.VersionID;
                    accreditationAttempt.UserGUID = userGuid;
                    accreditationAttempt.Accredited = accredited;

                    // TODO Find a better way of inserting UserAccreditaiton attempts
                    // Save the Accreditation so it updates it's User Accreditation list
                    //this.MarkDirty();

                    Attempts.Add(accreditationAttempt);

                    //this.Save();
                }

                /// <summary>
                /// Method used to retrieve the number of attempts (by a specific user) to complete an Accreditation successfully
                /// </summary>
                /// <param name="userGUID">The unique identifier for the user in question</param>
                /// <param name="result">Whether to look for positive or negative results</param>
                /// <returns>The number of attempts</returns>
                public int GetAttemptsByUser(Guid? userGUID, bool result)
                {
                    var items = (from userAccreditation in this.Attempts
                                 where userAccreditation.AccreditationGUID == this.GUID.Value
                                   && userAccreditation.UserGUID == userGUID
                                   && userAccreditation.Accredited == result
                                 select userAccreditation);

                    return items.Count();
                }

            #endregion

        #endregion

        #region Properties

            #region Association GUID Properties (Foreign Keys)

                /// <summary>The GUID of the company (BusinessObject) that this Accreditation belongs to</summary>
                public static PropertyInfo<Nullable<Guid>> CompanyGUIDProperty = RegisterProperty<Nullable<Guid>>(p => p.CompanyGUID);
                /// <summary>The GUID of the company (BusinessObject) that this Accreditation belongs to</summary>
                public Nullable<Guid> CompanyGUID
                {
                    get { return GetProperty(CompanyGUIDProperty); }
                }

                /// <summary>The GUID of the component (BusinessObject) that this Accreditation is associated with</summary>
                public static PropertyInfo<Nullable<Guid>> ComponentGUIDProperty = RegisterProperty<Nullable<Guid>>(p => p.ComponentGUID);
                /// <summary>The GUID of the component (BusinessObject) that this Accreditation is associated with</summary>
                public Nullable<Guid> ComponentGUID
                {
                    get { return GetProperty(ComponentGUIDProperty); }
                }

            #endregion

                /// <summary>
                /// The Version ID of this Accreditation. When used in conjunction with an AccreditationGUID, this
                /// uniquely identifies a given Accreditation.
                /// </summary>
                public static PropertyInfo<long> VersionIDProperty = RegisterProperty<long>(p => p.VersionID);
                /// <summary>
                /// The Version ID of this Accreditation. When used in conjunction with an AccreditationGUID, this
                /// uniquely identifies a given Accreditation.
                /// </summary>
                public long VersionID
                {
                    get { return GetProperty(VersionIDProperty); }
                }

                /// <summary>A human readable title for this Accreditation</summary>
                public static PropertyInfo<string> AccreditationTitleProperty = RegisterProperty<string>(p => p.Title);
                /// <summary>A human readable title for this Accreditation</summary>
                public string Title
                {
                    get { return GetProperty(AccreditationTitleProperty); }
                }

                /// <summary>
                /// A human readable description for this Accreditation
                /// </summary>
                public static PropertyInfo<string> AccreditationDescriptionProperty = RegisterProperty<string>(p => p.Description);
                /// <summary>
                /// A human readable description for this Accreditation
                /// </summary>
                public string Description
                {
                    get { return GetProperty(AccreditationDescriptionProperty); }
                }

                /// <summary>
                /// The XML document that describes the Accreditation.
                /// Sadly, the property type is required to be a string because XElement is not marked
                /// [Serializable] and therefore cannot be used with the Csla framework.
                /// </summary>
                public static PropertyInfo<string> AccreditationXMLProperty = RegisterProperty<string>(p => p.AccreditationXML);
                /// <summary>
                /// The XML document that describes the Accreditation.
                /// Sadly, the property type is required to be a string because XElement is not marked
                /// [Serializable] and therefore cannot be used with the Csla framework.
                /// </summary>
                public System.Xml.Linq.XElement AccreditationXML
                {
                    get { return System.Xml.Linq.XElement.Parse(GetProperty(AccreditationXMLProperty)); }
                }

                /// <summary>The minimum percentage requried for the Accreditation to be considered passed</summary>
                public static PropertyInfo<decimal> PassPercentageProperty = RegisterProperty<decimal>(p => p.PassPercentage);
                /// <summary>The minimum percentage requried for the Accreditation to be considered passed</summary>
                public decimal PassPercentage
                {
                    get { return GetProperty(PassPercentageProperty); }
                }

                /// <summary>The maximum amount of attempts allowed for this Accreditation</summary>
                public static PropertyInfo<int> MaxAttemptsProperty = RegisterProperty<int>(p => p.MaxAttempts);
                /// <summary>The maximum amount of attempts allowed for this Accreditation</summary>
                public int MaxAttempts
                {
                    get { return GetProperty(MaxAttemptsProperty); }
                }

                /// <summary>Whether or not a summary should be displayed for this Accreditation</summary>
                public static PropertyInfo<bool> ShowSummaryProperty = RegisterProperty<bool>(p => p.ShowSummary);
                /// <summary>Whether or not a summary should be displayed for this Accreditation</summary>
                public bool ShowSummary
                {
                    get { return GetProperty(ShowSummaryProperty); }
                }    

                /// <summary>The date and time when the Accreditation becomes current (in use)</summary>
                public static PropertyInfo<SmartDate> EffectiveStartDateTimeProperty = RegisterProperty<SmartDate>(p => p.EffectiveStartDateTime);
                /// <summary>The date and time when the Accreditation becomes current (in use)</summary>
                public SmartDate EffectiveStartDateTime
                {
                    get { return GetProperty(EffectiveStartDateTimeProperty); }
                }

                /// <summary>The date and time when the Accreditation ceases to be current (no longer in use)</summary>
                public static PropertyInfo<SmartDate> EffectiveEndDateTimeProperty = RegisterProperty<SmartDate>(p => p.EffectiveEndDateTime);
                /// <summary>The date and time when the Accreditation ceases to be current (no longer in use)</summary>
                public SmartDate EffectiveEndDateTime
                {
                    get { return GetProperty(EffectiveEndDateTimeProperty); }
                }

            #region Association Properties (Related Objects)

                /// <summary>A collection of Accreditation attempts associated with this Accreditation</summary>
                public static PropertyInfo<UserAccreditationList> UserAccreditationListProperty = RegisterProperty<UserAccreditationList>(p => p.Attempts);
                /// <summary>A collection of Accreditation attempts associated with this Accreditation</summary>
                public UserAccreditationList Attempts
                {
                    get
                    {
                        // If the property hasn't been loaded yet
                        if (!FieldManager.FieldExists(UserAccreditationListProperty))
                        {
                            if (IsNew)
                            {
                                // TODO check this new() method as it doesn't exist in the DataAccess!!!
                                // Load the property and notify CSLA that the property has changed
                                LoadProperty(UserAccreditationListProperty, UserAccreditationList.New());
                                OnPropertyChanged(UserAccreditationListProperty);
                            }
                            else
                            {
                                // Load the property
                                LoadProperty(UserAccreditationListProperty, UserAccreditationList.Get(this.GUID.Value));
                            }
                            return ReadProperty(UserAccreditationListProperty);
                        }
                        else
                        {
                            // Return the current property
                            return GetProperty(UserAccreditationListProperty);
                        }
                    }
                }

            #endregion

        #endregion
    }
}
